﻿using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
using UnityEngine.UI;

public class HUIFormScript : MonoBehaviour, IComparable {

	private struct stInitWidgetPosition
	{
		public int m_renderFrameStamp;

		public GameObject m_widget;

		public Vector3 m_worldPosition;
	}

	public static Vector2 DESIGN_UI = new Vector2 (1680, 946);

    private List<HUIComponent> m_uiComponents;

    private int m_sortingOrder;

    public Canvas canvas
    {
        get { return m_canvas; }
    }
    private Canvas m_canvas;

    [HideInInspector]
    public CanvasScaler m_canvasScaler;

	[HideInInspector]
	public string m_formPath;

	[HideInInspector]
	public bool m_useFormPool;

    private GraphicRaycaster m_graphicRaycaster;

	public bool m_isSingleton;

    public bool m_disableInput;

	/// <summary>
	/// 是不是隐藏下面的窗口
	/// </summary>
	public bool m_hideUnderForms;

	/// <summary>
	/// 阻挡其它输入
	/// </summary>
	public bool m_isBlock;

	private bool m_isNeedClose;

	private bool m_isClosed;

	private bool m_isInFadeIn;

	private bool m_isInFadeOut;

	private int m_sequence;

	private bool m_isInitialized;

	private bool m_isHided;

	public enFormPriority m_priority;

	private enFormPriority m_defaultPriority;

	private int m_openOrder;

	private HUIComponent m_formFadeInAnimationScript;

	private HUIComponent m_formFadeOutAnimationScript;

	public Vector2 m_referenceResolution = DESIGN_UI;

	public string m_formFadeInAnimationName = string.Empty;

	public string m_formFadeOutAnimationName = string.Empty;

	public bool m_alwaysKeepVisible;

	/// <summary>
	/// 是否开启一帧被多次点击
	/// </summary>
	public bool m_enableMultiClickedEvent = true;

	public GameObject[] m_formWidgets = new GameObject[0];

	[HideInInspector]
	public int m_clickedEventDispatchedCounter;

    private Dictionary<string, GameObject> m_formWidgetDict = new Dictionary<string, GameObject>();

	private List<HUIFormScript.stInitWidgetPosition> m_initWidgetPositions;

	private int m_renderFrameStamp;

    void Awake()
    {
        this.m_uiComponents = new List<HUIComponent>();
        InitializeCanvas();
        InitializeFormWidgetDict();
    }

    public void InitializeCanvas()
    {
        this.m_canvas = base.gameObject.GetComponent<Canvas>();
        this.m_canvasScaler = base.gameObject.GetComponent<CanvasScaler>();
        this.m_graphicRaycaster = base.GetComponent<GraphicRaycaster>();
        if (this.m_graphicRaycaster != null && this.m_disableInput)
        {
            this.m_graphicRaycaster.enabled = false;
        }
        this.MatchScreen();
    }

    public void InitializeFormWidgetDict()
    {
        m_formWidgetDict.Clear();

        for (int i = 0; i < m_formWidgets.Length; i++)
        {
            GameObject go = m_formWidgets[i];
            if (go)
            {
                m_formWidgetDict.Add(go.name, go);
            }
        }
    }

    public void MatchScreen()
    {
        if (this.m_canvasScaler == null)
        {
            return;
        }
		this.m_canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        this.m_canvasScaler.referenceResolution = this.m_referenceResolution;
        //this.m_canvasScaler.matchWidthOrHeight = 1f;
		this.m_canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;
    }

    public void CustomUpdate()
    {
        this.UpdateFadeIn();
        this.UpdateFadeOut();
    }

	public void CustomLateUpdate() {
		if (this.m_initWidgetPositions != null)
		{
			int i = 0;
			while (i < this.m_initWidgetPositions.Count)
			{
				HUIFormScript.stInitWidgetPosition stInitWidgetPosition = this.m_initWidgetPositions[i];
				if (this.m_renderFrameStamp - stInitWidgetPosition.m_renderFrameStamp <= 1)
				{
					if (stInitWidgetPosition.m_widget != null)
					{
						stInitWidgetPosition.m_widget.transform.position = stInitWidgetPosition.m_worldPosition;
					}
					i++;
				}
				else
				{
					this.m_initWidgetPositions.RemoveAt(i);
				}
			}
		}
		this.m_renderFrameStamp++;
		this.m_clickedEventDispatchedCounter = 0;
	}

    public int CompareTo(object obj)
    {
		HUIFormScript cUIFormScript = obj as HUIFormScript;
		if (this.m_sortingOrder > cUIFormScript.m_sortingOrder)
		{
			return 1;
		}
		if (this.m_sortingOrder == cUIFormScript.m_sortingOrder)
		{
			return 0;
		}
		return -1;
    }

    public int GetSortingOrder()
    {
        return this.m_sortingOrder;
    }

	public int GetSequence()
	{
		return this.m_sequence;
	}

	public GraphicRaycaster GetGraphicRaycaster()
	{
		return this.m_graphicRaycaster;
	}

	public Camera GetCamera()
	{
		if (this.m_canvas == null || this.m_canvas.renderMode == RenderMode.ScreenSpaceOverlay)
		{
			return null;
		}
		return this.m_canvas.worldCamera;
	}

	public Vector2 GetReferenceResolution()
	{
		return (!(this.m_canvasScaler == null)) ? this.m_canvasScaler.referenceResolution : Vector2.zero;
	}

	public GameObject GetWidget(int index)
	{
		if (index < 0 || index >= this.m_formWidgets.Length)
		{
			return null;
		}
		return this.m_formWidgets[index];
    }

    // 通过名字获取元素
    public GameObject GetWidget(string name, bool bIsPath = false)
    {
        if (!m_formWidgetDict.ContainsKey(name))
        {
            if (bIsPath)
            {
                Transform child = transform.Find(name);
                if (child)
                    return child.gameObject;
            }
            else {
                Transform[] childs = transform.GetComponentsInChildren<Transform>(true);
                foreach (Transform go in childs)
                {
                    if (go.name == name)
                        return go.gameObject;
                }
            }

            return null;
        }
        return this.m_formWidgetDict[name];
    }

    // 通过名字获取元素
    public T GetWidget<T>(string name) where T : MonoBehaviour
    {
        T[] childs = transform.GetComponentsInChildren<T>(true);
        foreach (T go in childs)
        {
            if (go.name == name)
                return go;
        }
        return null;
    }

    #region component
    public void AddUIComponent(HUIComponent uiComponent)
    {
        if (uiComponent != null && !this.m_uiComponents.Contains(uiComponent))
        {
            this.m_uiComponents.Add(uiComponent);
        }
    }

    public void RemoveUIComponent(HUIComponent uiComponent)
    {
        if (this.m_uiComponents.Contains(uiComponent))
        {
            this.m_uiComponents.Remove(uiComponent);
        }
    }

	private void SetComponentSortingOrder(int sortingOrder)
	{
		for (int i = 0; i < this.m_uiComponents.Count; i++)
		{
			this.m_uiComponents[i].SetSortingOrder(sortingOrder);
		}
	}

	public void InitializeComponent(GameObject root)
	{
		HUIComponent[] components = root.GetComponents<HUIComponent>();
		if (components != null && components.Length > 0)
		{
			for (int i = 0; i < components.Length; i++)
			{
				components[i].Initialize(this);
			}
		}
		for (int j = 0; j < root.transform.childCount; j++)
		{
			this.InitializeComponent(root.transform.GetChild(j).gameObject);
		}
	}

	private void CloseComponent()
	{
		for (int i = 0; i < this.m_uiComponents.Count; i++)
		{
			this.m_uiComponents[i].Close();
		}
	}

	private void HideComponent()
	{
		for (int i = 0; i < this.m_uiComponents.Count; i++)
		{
			this.m_uiComponents[i].Hide();
		}
	}

	private void AppearComponent()
	{
		for (int i = 0; i < this.m_uiComponents.Count; i++)
		{
			this.m_uiComponents[i].Appear();
		}
	}
	#endregion

	#region show hide
	public void Open(string formPath, Camera camera, int sequence, bool exist, int openOrder) {
		this.m_formPath = formPath;
		if (this.m_canvas != null)
		{
			this.m_canvas.worldCamera = camera;
			if (camera == null)
			{
                if (this.m_canvas.renderMode != RenderMode.ScreenSpaceOverlay)
				{
					this.m_canvas.renderMode = RenderMode.ScreenSpaceOverlay;
				}
			}
			else if (this.m_canvas.renderMode != RenderMode.ScreenSpaceCamera)
			{
				this.m_canvas.renderMode = RenderMode.ScreenSpaceCamera;
			}
			this.m_canvas.pixelPerfect = true;
		}
		this.RefreshCanvasScaler();
		this.Open(sequence, exist, openOrder);
	}

	public void Open(int sequence, bool exist, int openOrder)
	{
		this.m_isNeedClose = false;
		this.m_isClosed = false;
		this.m_isInFadeIn = false;
		this.m_isInFadeOut = false;
		this.m_clickedEventDispatchedCounter = 0;
		this.m_sequence = sequence;
		this.m_renderFrameStamp = 0;
		this.SetDisplayOrder(openOrder);
		if (!exist)
		{
			this.Initialize();
			this.DispatchFormEvent(enUIEventID.UI_OnFormVisibleChanged);
			if (this.IsNeedFadeIn())
			{
				this.StartFadeIn();
			}
		}
	}

	public void Close()
	{
		if (this.m_isNeedClose)
		{
			return;
		}
		this.m_isNeedClose = true;
		this.DispatchFormEvent(enUIEventID.UI_OnFormVisibleChanged);
		this.CloseComponent();
	}

	/// <summary>
	/// 是否需要关闭，在update中判断，并且执行关闭动画
	/// </summary>
	/// <returns><c>true</c> if this instance is need close; otherwise, <c>false</c>.</returns>
	public bool IsNeedClose()
	{
		return this.m_isNeedClose;
	}

	/// <summary>
	/// 开始关闭
	/// </summary>
	/// <returns><c>true</c>, 直接关闭, <c>false</c> 播放关闭动画.</returns>
	/// <param name="ignoreFadeOut">If set to <c>true</c> ignore fade out.</param>
	public bool TurnToClosed(bool ignoreFadeOut)
	{
		this.m_isNeedClose = false;
		this.m_isClosed = true;
		if (ignoreFadeOut || !this.IsNeedFadeOut())
		{
			return true;
		}
		this.StartFadeOut();
		return false;
	}

	/// <summary>
	/// 是否已经关闭，在close的下一帧会返回true
	/// </summary>
	/// <returns><c>true</c> if this instance is closed; otherwise, <c>false</c>.</returns>
	public bool IsClosed()
	{
		return this.m_isClosed;
	}

	public bool IsCanvasEnabled()
	{
		return !(this.m_canvas == null) && this.m_canvas.enabled;
	}

	public void SetActive(bool active)
	{
		base.gameObject.SetActive(active);
		if (active)
		{
			this.Appear(true);
		}
		else
		{
			this.Hide(true);
		}
	}

	public void Hide(bool dispatchVisibleChangedEvent = true)
	{
		if (this.m_alwaysKeepVisible)
		{
			return;
		}
		if (this.m_isHided) {
			return;
		}
		this.m_isHided = true;
		if (this.m_canvas != null)
		{
			this.m_canvas.enabled = false;
		}
		if (this.m_graphicRaycaster)
		{
			this.m_graphicRaycaster.enabled = false;
		}
		this.HideComponent();
		if (dispatchVisibleChangedEvent)
		{
			this.DispatchFormEvent(enUIEventID.UI_OnFormVisibleChanged);
		}
	}

	public void Appear(bool dispatchVisibleChangedEvent = true)
	{
		if (this.m_alwaysKeepVisible)
		{
			return;
		}
		if (!this.m_isHided) {
			return;
		}
		this.m_isHided = false;
		if (this.m_canvas != null)
		{
			this.m_canvas.enabled = true;
			this.m_canvas.sortingOrder = this.m_sortingOrder;
		}
		if (this.m_graphicRaycaster && !this.m_disableInput)
		{
			this.m_graphicRaycaster.enabled = true;
		}
		this.AppearComponent();
		if (dispatchVisibleChangedEvent)
		{
			this.DispatchFormEvent(enUIEventID.UI_OnFormVisibleChanged);
		}
	}

	public bool IsHided()
	{
		return this.m_isHided;
	}
	#endregion

	public void SetDisplayOrder(int openOrder)
	{
		Debug.AssertFormat(openOrder > 0, "openOrder = {0}, 该值必须大于0", new object[]
		{
			openOrder
		});
		this.m_openOrder = openOrder;
		if (this.m_canvas != null)
		{
			this.m_sortingOrder = this.CalculateSortingOrder(this.m_priority, this.m_openOrder);
			this.m_canvas.sortingOrder = this.m_sortingOrder;
			try
			{
				if (this.m_canvas.enabled)
				{
					this.m_canvas.enabled = false;
					this.m_canvas.enabled = true;
				}
			}
			catch (Exception ex)
			{
				Debug.AssertFormat(false, "Error form {0}: message: {1}, callstack: {2}", new object[]
				{
					base.name,
					ex.Message,
					ex.StackTrace
				});
			}
		}
		this.SetComponentSortingOrder(this.m_sortingOrder);
	}

	private void RefreshCanvasScaler()
	{
		try
		{
			if (this.m_canvasScaler != null)
			{
				this.m_canvasScaler.enabled = false;
				this.m_canvasScaler.enabled = true;
			}
		}
		catch (Exception ex)
		{
			Debug.AssertFormat(false, "Error form {0}: message: {1}, callstack: {2}", new object[]
			{
				base.name,
				ex.Message,
				ex.StackTrace
			});
		}
	}

	public void Initialize()
	{
		if (this.m_isInitialized)
		{
			return;
		}
		this.m_defaultPriority = this.m_priority;
		this.InitializeComponent(base.gameObject);
		this.m_isInitialized = true;
	}

	public void SetPriority(enFormPriority priority)
	{
		if (this.m_priority == priority)
		{
			return;
		}
		this.m_priority = priority;
		this.SetDisplayOrder(this.m_openOrder);
		this.DispatchFormEvent(enUIEventID.UI_OnFormPriorityChanged);
	}

	public void RestorePriority()
	{
		this.SetPriority(this.m_defaultPriority);
	}

	private bool IsOverlay()
	{
		return !(this.m_canvas == null) && (this.m_canvas.renderMode == RenderMode.ScreenSpaceOverlay || this.m_canvas.worldCamera == null);
	}

	private int CalculateSortingOrder(enFormPriority priority, int openOrder)
	{
		if (openOrder * 10 >= 1000)
		{
			openOrder %= 100;
		}
		return (int)(((!this.IsOverlay()) ? 0 : 10000) + (int)priority * 1000 + openOrder * 10);
	}

	private void DispatchFormEvent(enUIEventID formEventType)
	{
		if (formEventType == enUIEventID.None)
		{
			return;
		}
		HUIEvent uIEvent = HUIEventManager.Instance.GetUIEvent();
		uIEvent.m_eventID = formEventType;
		uIEvent.m_srcFormScript = this;
		HUIEventManager.Instance.DispatchUIEvent(uIEvent);
	}

	public float ChangeScreenValueToForm(float value)
	{
		if (this.m_canvasScaler.matchWidthOrHeight == 0f)
		{
			return value * this.m_canvasScaler.referenceResolution.x / (float)Screen.width;
		}
		if (this.m_canvasScaler.matchWidthOrHeight == 1f)
		{
			return value * this.m_canvasScaler.referenceResolution.y / (float)Screen.height;
		}
		return value;
	}

	public void InitializeWidgetPosition(GameObject widget, Vector3 worldPosition)
	{
		if (this.m_initWidgetPositions == null)
		{
			this.m_initWidgetPositions = new List<HUIFormScript.stInitWidgetPosition>();
		}
		HUIFormScript.stInitWidgetPosition item = default(HUIFormScript.stInitWidgetPosition);
		item.m_renderFrameStamp = this.m_renderFrameStamp;
		item.m_widget = widget;
		item.m_worldPosition = worldPosition;
		this.m_initWidgetPositions.Add(item);
	}

	#region fade
	public bool IsNeedFadeIn()
	{
		return !string.IsNullOrEmpty(this.m_formFadeInAnimationName);
	}

	private void StartFadeIn()
	{
		if (string.IsNullOrEmpty(this.m_formFadeInAnimationName))
		{
			return;
		}
		this.m_formFadeInAnimationScript = base.gameObject.GetComponent<HUIAnimatorScript> ();
		if (this.m_formFadeInAnimationScript != null) {
			((HUIAnimatorScript)this.m_formFadeInAnimationScript).PlayAnimator (this.m_formFadeInAnimationName);
			this.m_isInFadeIn = true;
		}
	}

	public bool IsNeedFadeOut()
	{
		return false;
	}

	private void StartFadeOut()
	{
		if (string.IsNullOrEmpty(this.m_formFadeOutAnimationName))
		{
			return;
		}
		this.m_formFadeOutAnimationScript = base.gameObject.GetComponent<HUIAnimatorScript>();
		if (this.m_formFadeOutAnimationScript != null)
		{
			((HUIAnimatorScript)this.m_formFadeOutAnimationScript).PlayAnimator(this.m_formFadeOutAnimationName);
			this.m_isInFadeOut = true;
		}
	}

	public bool IsInFadeIn()
	{
		return this.m_isInFadeIn;
	}

	public bool IsInFadeOut()
	{
		return this.m_isInFadeOut;
	}

	private void UpdateFadeIn()
	{
		if (this.m_isInFadeIn)
		{
			if (this.m_formFadeInAnimationScript == null || ((HUIAnimatorScript)this.m_formFadeInAnimationScript).IsAnimationStopped(this.m_formFadeInAnimationName))
			{
				this.m_isInFadeIn = false;
			}

		}
	}

	private void UpdateFadeOut()
	{
		if (this.m_isInFadeOut)
		{
			if (this.m_formFadeOutAnimationScript == null || ((HUIAnimatorScript)this.m_formFadeOutAnimationScript).IsAnimationStopped(this.m_formFadeOutAnimationName))
			{
				this.m_isInFadeOut = false;
			}
		}
	}
	#endregion
}
